﻿Friend Class Handler_Restore
    Private Shared mRunningTasks As New Generic.List(Of RestoreTask)

    Public Shared Function StartNew(ByVal request As RestoreRequest) As RestoreTask
        Dim clsTask As New RestoreTask(request)
        clsTask.Start()
        Return clsTask
    End Function
End Class

Public Class RestoreRequest
    Public Files As Generic.List(Of Entities.Backup.BackedUpFileContainerInfo)
    Public Password As String
    Public CustomTargetPath As String
End Class


Public Class RestoreTask
    Implements SevenZip.ICodeProgress

    Private mThread As Threading.Thread
    Private mFiles As Generic.List(Of Entities.Backup.BackedUpFileContainerInfo)
    Private mPassword As String
    Private mCustomTargetPath As String

    Private mCurrentFileIndex As Integer = 0
    Private mTotalSize As Long = 0
    Private mFilesLeft As New Generic.List(Of Entities.Backup.BackedUpFileContainerInfo)

    Public Event Started(ByVal sender As RestoreTask)
    Public Event StartedGUI(ByVal sender As RestoreTask)
    Public Event Completed(ByVal sender As RestoreTask)
    Public Event CompletedGUI(ByVal sender As RestoreTask)
    Public Event Aborted(ByVal sender As RestoreTask)
    Public Event AbortedGUI(ByVal sender As RestoreTask)
    Public Event Progress(ByVal sender As RestoreTask, ByVal e As ProgressEventArgs)
    Public Event ProgressGUI(ByVal sender As RestoreTask, ByVal e As ProgressEventArgs)
    Public Event Exception(ByVal sender As RestoreTask, ByVal file As Entities.Backup.BackedUpFileContainerInfo, ByVal exception As Exception)
    Public Event ExceptionGUI(ByVal sender As RestoreTask, ByVal file As Entities.Backup.BackedUpFileContainerInfo, ByVal exception As Exception)

    Public Sub New(ByVal request As RestoreRequest)
        mFiles = request.Files
        mPassword = request.Password
        mCustomTargetPath = request.CustomTargetPath
        mFilesLeft.AddRange(request.Files)
        For Each clsFile As Entities.Backup.BackedUpFileContainerInfo In mFiles
            mTotalSize += clsFile.FileSize
        Next
    End Sub

    Friend Sub Start()
        mThread = New Threading.Thread(AddressOf Daemon)
        mThread.Name = "Restore Backup Worker Thread"
        mThread.Priority = Threading.ThreadPriority.Lowest
        mThread.IsBackground = True
        mThread.Start()
    End Sub

    Friend Sub OnProgress()
        RaiseEvent Progress(Me, mCurrentEventArgs)
        Framework.Threading.Invoke(AddressOf OnProgress_Callback)
    End Sub
    Private Sub OnProgress_Callback()
        RaiseEvent ProgressGUI(Me, mCurrentEventArgs)
    End Sub
    Friend Sub OnStarted()
        RaiseEvent Started(Me)
        Framework.Threading.Invoke(AddressOf OnStarted_Callback)
    End Sub
    Private Sub OnStarted_Callback()
        RaiseEvent StartedGUI(Me)
    End Sub
    Friend Sub OnCompleted()
        RaiseEvent Completed(Me)
        Framework.Threading.Invoke(AddressOf OnCompleted_Callback)
    End Sub
    Private Sub OnCompleted_Callback()
        RaiseEvent CompletedGUI(Me)
    End Sub
    Friend Sub OnAborted()
        RaiseEvent Aborted(Me)
        Framework.Threading.Invoke(AddressOf OnAborted_Callback)
    End Sub
    Private Sub OnAborted_Callback()
        RaiseEvent AbortedGUI(Me)
    End Sub
    Friend Sub OnException(ByVal file As Entities.Backup.BackedUpFileContainerInfo, ByVal exception As Exception)
        RaiseEvent Exception(Me, file, exception)
        Framework.Threading.Invoke(AddressOf OnException_Callback, file, exception)
    End Sub
    Private Sub OnException_Callback(ByVal file As Entities.Backup.BackedUpFileContainerInfo, ByVal exception As Exception)
        RaiseEvent ExceptionGUI(Me, file, exception)
    End Sub

    Private mCurrentEventArgs As New ProgressEventArgs

    Private Sub Daemon()
        Try
            OnStarted()
            Do
                Dim clsFile As Entities.Backup.BackedUpFileContainerInfo = Nothing
                Try
                    If mFilesLeft.Count = 0 Then
                        mCurrentEventArgs.CurrentFileIndex = mFiles.Count
                        mCurrentEventArgs.CurrentFileSizeRestored = mTotalSize
                        mCurrentEventArgs.CurrentTask = String.Empty
                        mCurrentEventArgs.CurrentFileSize = 1
                        mCurrentEventArgs.CurrentFileSizeRestored = 1
                        OnProgress()
                        Exit Do
                    End If
                    clsFile = mFilesLeft(0)
                    mCurrentEventArgs.CurrentSourceFilePath = clsFile.ContainerPath
                    mCurrentEventArgs.CurrentFileIndex = mCurrentFileIndex
                    mCurrentEventArgs.CurrentFileSize = clsFile.FileSize
                    mCurrentEventArgs.CurrentDestinationFilePath = GetDestinationPath(clsFile.FilePath, mCustomTargetPath)
                    Handler_PackagingDaemon.RestoreFile(mCurrentEventArgs, mPassword, Me)
                Catch ex As Threading.ThreadAbortException
                    OnAborted()
                    Return
                Catch ex As Exception
                    OnException(clsFile, ex)
                Finally
                    If clsFile IsNot Nothing Then
                        mCurrentFileIndex += 1
                        mFilesLeft.Remove(clsFile)
                    End If
                End Try
            Loop
            OnCompleted()
        Catch ex As Threading.ThreadAbortException
            OnAborted()
            Return
        End Try
    End Sub
    Public Sub Abort()
        mThread.Abort()
        mThread.Join(10000)
        mThread = Nothing
    End Sub

    Private Function GetDestinationPath(ByVal filePath As String, ByVal customTargetPath As String) As String
        If Not String.IsNullOrEmpty(customTargetPath) Then
            filePath = filePath.Replace(":\", "_Disk\")
            filePath = filePath.Replace("\\", "NetWork_")
            filePath = IO.Path.Combine(customTargetPath, filePath)
        End If
        Dim strDir As String = IO.Path.GetDirectoryName(filePath)
        If Not IO.Directory.Exists(strDir) Then IO.Directory.CreateDirectory(strDir)
        Return filePath
    End Function

    Public Class ProgressEventArgs
        Inherits System.EventArgs

        Public CurrentFileIndex As Integer
        Public CurrentSourceFilePath As String
        Public CurrentDestinationFilePath As String
        Public CurrentTask As String
        Public CurrentFileSize As Long
        Public CurrentFileSizeRestored As Long
    End Class

    Private Sub SetProgress(ByVal inSize As Long, ByVal outSize As Long) Implements SevenZip.ICodeProgress.SetProgress
        mCurrentEventArgs.CurrentFileSizeRestored = outSize
        OnProgress()
    End Sub
End Class